using System;
using System.Collections.Generic;
using Net.System;
using UnityEngine;
using Object = UnityEngine.Object;

namespace GameCore
{
    public abstract class PoolListCache
    {
        public abstract void Add(Component poolObj);
        public abstract void Clear();
        public abstract object GetList();
        public abstract object GetIndex(int index);
    }

    public class PoolListCache<T> : PoolListCache where T : Component
    {
        public List<T> List = new();
        private readonly T source;
        private readonly Transform content;

        public PoolListCache(T component, Transform parent)
        {
            source = component;
            content = parent;
        }

        public int Count => List.Count;

        public T this[int index]
        {
            get => List[index];
            set => List[index] = value;
        }

        public override void Add(Component poolObj)
        {
            List.Add(poolObj as T);
        }

        public override void Clear()
        {
            foreach (var component in List)
            {
                if (component == null)
                    continue;
                component.UnSpawn();
            }
            List.Clear();
        }

        public override object GetList()
        {
            return List;
        }

        public override object GetIndex(int index)
        {
            return List[index];
        }

        public T GetAddList(T component, Transform parent = null)
        {
            var instanceObject = Global.Pool.Spawn(component, parent);
            List.Add(instanceObject);
            return instanceObject;
        }

        public T Spawn() => GetAddList(source, content);

        public T Spawn(T component, Transform parent = null) => GetAddList(component, parent);
    }

    /// <summary>
    /// 对象池中对象的通用接口
    /// 实现该接口的对象可以被对象池管理系统复用 
    /// </summary>
    public interface IPoolObject
    {
        /// <summary>
        /// 当对象从对象池激活时调用 
        /// 典型用途：
        /// 1. 重置对象初始状态（如位置归零、血量回满）
        /// 2. 重新初始化动态属性 
        /// 3. 注册事件监听
        /// 4. 激活关联的GameObject
        /// </summary>
        void OnSpawn();

        /// <summary>
        /// 当对象被回收到对象池时调用 
        /// 典型用途：
        /// 1. 解除事件绑定（防止内存泄漏）
        /// 2. 清理运行时数据（如清空任务队列）
        /// 3. 禁用物理组件
        /// 4. 隐藏/禁用关联的GameObject
        /// </summary>
        void OnUnSpawn();
    }

    public partial class ObjectPool : MonoBehaviour
    {
        protected readonly MyDictionary<Object, Queue<Object>> Cache = new();
        protected readonly MyDictionary<Type, MyDictionary<Enum, PoolListCache>> CacheList = new();

        public T Spawn<T>(string assetPath, Transform parent = null) where T : Object
        {
            var assetObject = Global.Resources.LoadAsset<T>(assetPath);
            return Spawn(assetObject, parent);
        }

        public T Spawn<T>(T assetObject, Transform parent = null) where T : Object
        {
            if (!Cache.TryGetValue(assetObject, out var queue))
                Cache.Add(assetObject, queue = new Queue<Object>());
            T instanceObj;
            while (queue.Count > 0) //如果池内的物体被意外删除了, 就会被清除忽略掉
            {
                instanceObj = queue.Dequeue() as T;
                if (instanceObj != null)
                    goto SET;
            }
            instanceObj = Instantiate(assetObject, parent);
        SET:
            GameObject gameObject = null;
            if (instanceObj is GameObject isGameObject)
                gameObject = isGameObject;
            else if (instanceObj is Component component)
                gameObject = component.gameObject;
            if (gameObject != null)
            {
                if (!gameObject.TryGetComponent<AssetHandle>(out var assetHandle))
                {
                    assetHandle = gameObject.AddComponent<AssetHandle>();
                    assetHandle.AssetSource = assetObject;
                }
                gameObject.transform.SetParent(parent);
                gameObject.transform.SetAsLastSibling();
                gameObject.SetActive(true);
            }
            if (instanceObj is IPoolObject poolObject)
                poolObject.OnSpawn();
            return instanceObj;
        }

        public void UnSpawn(Object instanceObject)
        {
            AssetHandle assetHandle = null;
            if (instanceObject is Component component)
                assetHandle = component.gameObject.GetComponent<AssetHandle>();
            else if (instanceObject is GameObject gameObject)
                assetHandle = gameObject.GetComponent<AssetHandle>();
            if (assetHandle == null)
                return;
            if (!Cache.TryGetValue(assetHandle.AssetSource, out var queue))
                Cache.Add(assetHandle.AssetSource, queue = new Queue<Object>());
            if (instanceObject is IPoolObject poolObject)
                poolObject.OnUnSpawn();
            assetHandle.gameObject.SetActive(false);
            queue.Enqueue(instanceObject);
        }

        /// <summary>
        /// 获取对象池物体并且添加到缓存列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="command"></param>
        /// <param name="component"></param>
        /// <param name="parent"></param>
        /// <returns></returns>
        public T SpawnList<T>(Enum command, T component, Transform parent = null) where T : Component
        {
            var poolList = GetSpawnList<T>(command);
            return poolList.Spawn(component, parent);
        }

        /// <summary>
        /// 回收对象池缓存列表
        /// </summary>
        /// <param name="command"></param>
        public PoolListCache<T> UnSpawnList<T>(Enum command) where T : Component
        {
            return UnSpawnList<T>(command, null, null);
        }

        public PoolListCache<T> UnSpawnList<T>(Enum command, T component, Transform parent = null) where T : Component
        {
            var type = typeof(T);
            if (!CacheList.TryGetValue(type, out var cacheDict))
                CacheList.Add(type, cacheDict = new());
            if (!cacheDict.TryGetValue(command, out var comList))
                cacheDict.Add(command, comList = new PoolListCache<T>(component, parent));
            comList.Clear();
            return comList as PoolListCache<T>;
        }

        public PoolListCache<T> GetSpawnList<T>(Enum command) where T : Component
        {
            var type = typeof(T);
            if (!CacheList.TryGetValue(type, out var cacheDict))
                CacheList.Add(type, cacheDict = new());
            if (!cacheDict.TryGetValue(command, out var comList))
                cacheDict.Add(command, comList = new PoolListCache<T>(null, null));
            return comList as PoolListCache<T>;
        }

        public T GetSpawnIndex<T>(Enum command, int index) where T : Component
        {
            var poolList = GetSpawnList<T>(command);
            return poolList.GetIndex(index) as T;
        }
    }
}

public static class ObjectPoolEx
{
    public static void UnSpawns<T>(this List<T> self) where T : Object
    {
        for (int i = 0; i < self.Count; i++)
            self[i]?.UnSpawn();
        self.Clear();
    }

    public static void UnSpawn<T>(this T self) where T : Object
    {
        GameCore.Global.Pool.UnSpawn(self);
    }

    public static void UnSpawns<T>(this T[] self) where T : Object
    {
        for (int i = 0; i < self.Length; i++)
            self[i]?.UnSpawn();
    }

    public static void UnSpawns<Key, Value>(this Dictionary<Key, Value> self) where Value : Object
    {
        foreach (var item in self)
            item.Value?.UnSpawn();
        self.Clear();
    }
}